<!--
 * @Description: 实际施工进度
 * @Author: wang_k
 * @Date: 2025-08-18 11:33:17
 * @LastEditTime: 2025-08-29 11:16:58
 * @FilePath: /note/src/views/Ceshi/components/chart.vue
-->
<template>
  <div class="rock_chart">
    <div title="实际施工进度" style="margin-bottom: 10px">
      <div class="title_right_content">
        <div class="right_title_info">
          <div class="legend">
            <div
              class="legend-item"
              v-for="(item, index) in legendData"
              :key="index"
            >
              <span
                class="legend-dot"
                :style="{
                  background: item.color,
                }"
              ></span>
              <span class="legend-text">{{ item.text }}</span>
            </div>
            施工部位：开挖支护
          </div>
        </div>
        <!-- <img src="~@/assets/img/Cbe/narrow.png" alt="" @click="zoomHandle" /> -->
      </div>
    </div>
    <div class="trend_chart_box">
      <div class="chart_box_left">
        <div
          class="panel-item"
          v-for="item in panelData"
          :key="item.label"
          :style="`background:${item.color}`"
        >
          <div>{{ item.label }}</div>
          <div>{{ item.value }}m</div>
        </div>
      </div>
      <div class="chart_box_right">
        <div class="progress-box">
          <div class="progress-content">
            <div
              class="progress-history"
              :style="{
                width: history_width + '%',
              }"
            >
              历史态势
            </div>
            <div
              class="progress-future"
              :style="{
                width: 100 - history_width + '%',
              }"
            >
              未来态势
            </div>
          </div>
          <div class="progress-scale">
            <div
              class="progress-scale-item"
              v-for="(item, index) in xData"
              :key="item.value"
              :style="{
                width: item.width + '%',
              }"
            >
              <div
                class="progress-scale-line"
                v-show="index !== 0 && index !== xData.length - 1"
              ></div>
              <div
                class="progress-scale-son"
                v-show="index !== 0 && index !== xData.length - 1"
              >
                {{ dayFormat(item.value) }}
              </div>
            </div>
          </div>
          <div
            class="marking-line"
            :style="{
              left: currentPosition + '%',
            }"
          >
            <span class="line-row1">{{ markingData.date }}</span>
            <span class="line-row2">{{ markingData.meter }}</span>
          </div>
        </div>
        <div class="play-content">
          <!-- <span v-if="!isPlaying">播放</span>
					<span v-else>暂停</span> -->
          <div class="play-button">
            <div class="play">
              <img src="@/assets/img/Cbe/play_left.png" alt="" />
            </div>
            <div class="play play1" @click="handlePlay">
              <img src="@/assets/img/Cbe/play.png" alt="" />
            </div>
            <div class="play">
              <img src="@/assets/img/Cbe/play_right.png" alt="" />
            </div>
          </div>
          <div class="play-select">
            播放速度
            <fks-select
              style="width: 100px; margin-left: 10px"
              v-model="playbackSpeed"
              placeholder="请选择"
            >
              <fks-option
                v-for="item in playbackSpeedOptions"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              >
              </fks-option>
            </fks-select>
            <fks-button
              style="margin-left: 10px"
              icon="fks-icon-reset"
              @click="handleReset"
            ></fks-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
// import SecondTitle from './RightInfoContents/SecondTitle.vue'
// import { getPlanDetail } from './api/progressmanage'
export default {
  name: 'ConstructionProgressChart',
  components: {
    // SecondTitle
  },
  props: {},
  data() {
    return {
      legendData: [
        {
          color: '#78CD78',
          text: '已完成',
        },
        {
          color: '#BFBFBF',
          text: '未开始',
        },
      ],
      panelData: [
        {
          label: '设计长度',
          value: '1530',
          color:
            'linear-gradient(284deg,rgba(0, 107, 237, 0) 3%,rgba(0, 107, 237, 0.15) 95%)',
        },
        {
          label: '2024年实际完成',
          value: '1530',
          color:
            'linear-gradient(284deg, rgba(149, 125, 243, 0) 3%, rgba(149, 125, 243, 0.15) 95%)',
        },
        {
          label: '2025年计划完成',
          value: '1530',
          color:
            'linear-gradient(284deg, rgba(249, 175, 85, 0) 3%, rgba(249, 175, 85, 0.15) 95%)',
        },
      ],
      markingData: {
        date: '2024-08-01',
        meter: '123m',
      },
      initcurrentPosition: '',
      currentPosition: '',
      history_width: 40,
      isPlaying: false,
      animationInterval: null,
      animationFrameId: null,

      playbackSpeed: 1, // 播放速度控制
      playEndDate: '2025-08-01',
      startPosition: 0, // 播放起点位置（markingData.date对应进度条%）
      endPosition: 0, // 播放终点位置（playEndDate对应进度条%）
      startTime: null,
      elapsedTime: 0,

      nodeData: null,
      playbackSpeedOptions: [
        // { value: '1', label: '1' },
        // { value: '0.5', label: '2' },
        // { value: '0.3', label: '3' },
        // { value: '2', label: '0.5' },
        { value: 1, label: '1' },
        { value: 2, label: '2' },
        { value: 3, label: '3' },
        { value: '0.5', label: '0.5' },
      ],
    };
  },
  computed: {
    xData() {
      const dayArr = this.generateMonthlyFirstDays(); // 时间轴：["2024-07-01", "2024-08-01", ...]
      if (dayArr.length < 2) return []; // 至少需要2个时间点才计算间隔

      // 1. 计算总时间跨度（毫秒）：从第一个月到最后一个月的第一天
      const startTime = this.$dayjs(dayArr[0]).valueOf();
      const endTime = this.$dayjs(dayArr[dayArr.length - 1]).valueOf();

      const totalDuration = endTime - startTime;
      if (totalDuration <= 0) return []; // 避免无效时间轴

      // 2. 计算每个相邻月份的间隔宽度（共 dayArr.length - 1 个间隔）
      const intervalWidths = [];
      for (let i = 0; i < dayArr.length - 1; i++) {
        const currentTime = this.$dayjs(dayArr[i]).valueOf();
        const nextTime = this.$dayjs(dayArr[i + 1]).valueOf();
        const intervalDuration = nextTime - currentTime; // 当前月到下月的实际跨度
        const widthRatio = (intervalDuration / totalDuration) * 100; // 占比
        intervalWidths.push(widthRatio);
      }

      // 3. 处理最后一个刻度的宽度（补全精度误差，确保总和100%）
      const sumPrevWidths = intervalWidths.reduce((sum, w) => sum + w, 0);
      const lastWidth = 100 - sumPrevWidths; // 最后一个间隔的宽度=100%-前面总和
      intervalWidths.push(lastWidth);

      // 4. 生成xData（每个刻度对应一个间隔宽度）
      const res = dayArr.map((item, index) => ({
        value: item,
        width: intervalWidths[index].toFixed(6), // 保留6位小数，减少精度损失
      }));

      // 验证总宽度（应接近100%）
      const totalWidth = res.reduce(
        (sum, item) => sum + parseFloat(item.width),
        0,
      );
      console.log('修正后xData总宽度占比：', totalWidth.toFixed(2), '%');
      return res;
    },
    totalMonths() {
      return this.xData.length;
    },
    totalDuration() {
      return this.totalMonths * 5000; // 总时长 = 月数 * 5000毫秒（5秒/月）
    },
    //计算播放的实际时间跨度（markingData.date → playEndDate）
    playTimeSpan() {
      const start = this.$dayjs(this.markingData.date).valueOf();
      const end = this.$dayjs(this.playEndDate).valueOf();
      return Math.max(1, end - start); // 避免时间倒序，最小为1ms
    },
    // 动画总时长（按“1天=100ms”计算，与播放速度绑定）
    totalAnimationDuration() {
      // 转换时间跨度为天数，再映射为动画时长（可调整100ms控制节奏）
      const days = this.playTimeSpan / (24 * 60 * 60 * 1000);
      // return days * 10 * this.playbackSpeed;
      return days * 10 * 1;
    },
  },
  watch: {
    playbackSpeed(newSpeed, oldSpeed) {
      // 仅在播放中且倍速确实变化时，校准时间基准
      if (this.isPlaying && newSpeed !== oldSpeed) {
        this.pauseAnimation(); // 先暂停当前动画，避免冲突
        // 核心：基于当前进度，重新计算新的elapsedTime和startTime
        const currentProgress =
          (this.currentPosition - this.startPosition) /
          (this.endPosition - this.startPosition);
        // 新总时长 = 原总时长 * 旧倍速 / 新倍速（保证进度不变）
        const newTotalDuration =
          (this.totalAnimationDuration * oldSpeed) / newSpeed;
        // 新已播放时间 = 总进度 * 新总时长
        this.elapsedTime = currentProgress * newTotalDuration;
        // 重新设置startTime，确保后续计算正确
        this.startTime = Date.now() - this.elapsedTime;
        this.startAnimation(); // 用新基准重启动画
      }
    },
  },
  created() {},
  mounted() {
    this.handlerProgressChange();
    // window.eventHub.$on('selectUnitProject', this.selectProject)
    // window.eventHub.$on('onProgressChange', this.handlerProgressChange)
  },
  methods: {
    dayFormat(value) {
      return this.$dayjs(value).format('MM-DD');
      // return this.$dayjs(value).format('YYYY-MM-DD')
    },
    calculateMarkerPosition(is = true, markDate = this.markingData.date) {
      // 1. 获取时间轴数据
      const timeline = this.xData.map((item) => item.value);

      // 2. 找到开始日期（第一个点）
      const startDate = timeline[0];

      // 3. 计算时间总跨度（毫秒）
      const startTime = this.$dayjs(startDate).valueOf();
      const endTime = this.$dayjs(timeline[timeline.length - 1]).valueOf();
      const totalDuration = endTime - startTime;

      // 4. 计算目标日期距离开始日期的时间
      const targetTime = this.$dayjs(markDate).valueOf();
      const elapsedTime = targetTime - startTime;

      // 5. 计算时间比例 (0-1)
      const timeRatio = Math.min(1, Math.max(0, elapsedTime / totalDuration));
      // 计算总的时间跨度(按照每月30天计算)
      if (is) {
        // 6. 转换为进度条位置
        this.currentPosition = timeRatio * 100;
        this.initcurrentPosition = timeRatio * 100;
      } else {
        return timeRatio * 100;
      }

      console.log(`标记线位置计算完成: ${this.currentPosition.toFixed(2)}%`);

      // 7. 更新标记数据
      // this.updateMarkingData();
    },
    // 计算播放范围（仅基于markingData.date和playEndDate，不影响xData）
    calculatePlayRange() {
      const timeline = this.xData.map((item) => item.value);
      if (timeline.length < 2) return;

      const startTime = this.$dayjs(timeline[0]).valueOf();
      const endTime = this.$dayjs(timeline[timeline.length - 1]).valueOf();
      const totalDuration = endTime - startTime;
      if (totalDuration === 0) return;

      // 1. 计算播放起点（markingData.date）
      const startPlayTime = this.$dayjs(this.markingData.date).valueOf();
      this.startPosition = Math.min(
        100,
        Math.max(0, ((startPlayTime - startTime) / totalDuration) * 100),
      );

      // 2. 计算播放终点（playEndDate）
      const endPlayTime = this.$dayjs(this.playEndDate).valueOf();
      this.endPosition = Math.min(
        100,
        Math.max(0, ((endPlayTime - startTime) / totalDuration) * 100),
      );
    },
    handlePlay() {
      if (this.isPlaying) {
        this.pauseAnimation();
      } else {
        this.startAnimation();
      }
      this.isPlaying = !this.isPlaying;
    },
    handleReset() {
      this.pauseAnimation();
      this.isPlaying = false;
      this.currentPosition = this.startPosition;
      this.elapsedTime = 0;
      this.updateMarkingData(); // 重置时同步更新日期和米数
    },
    startAnimation() {
      if (this.animationInterval) return;
      // debugger;
      // 若已播放到终点，重置到起点
      if (this.currentPosition >= this.endPosition) {
        this.handleReset();
      }

      this.startTime = Date.now() - this.elapsedTime;

      const animate = () => {
        const now = Date.now();
        this.elapsedTime = now - this.startTime;

        // 计算动画进度（0→1）：基于播放时间跨度，而非原totalDuration
        const progress = Math.min(
          1,
          this.elapsedTime / this.totalAnimationDuration,
        );

        // 核心：仅在 startPosition → endPosition 之间更新currentPosition
        this.currentPosition =
          this.startPosition +
          (this.endPosition - this.startPosition) * progress;
        console.log(
          this.currentPosition,
          progress,
          this.totalAnimationDuration,
          'currentPosition',
        );

        // 更新标记数据（日期、米数）
        this.updateMarkingData();

        // 未到终点则继续，到终点则停止
        if (progress < 1) {
          this.animationInterval = requestAnimationFrame(animate);
        } else {
          this.isPlaying = false;
          this.animationInterval = null;
        }
      };

      this.animationInterval = requestAnimationFrame(animate);
    },

    pauseAnimation() {
      if (this.animationInterval) {
        cancelAnimationFrame(this.animationInterval);
        this.animationInterval = null;
      }
    },
    // updateMarkingData() {
    //   // 计算当前点索引
    //   const totalPoints = this.xData.length;
    //   if (totalPoints === 0) return; // 边界保护
    //   const pointIndex = Math.min(
    //     totalPoints - 1,
    //     Math.floor(((this.currentPosition - 20) / 80) * totalPoints),
    //   );

    //   // 更新日期
    //   if (this.xData[pointIndex]) {
    //     // this.markingData.date = this.dayFormat(this.xData[pointIndex].value);
    //     this.markingData.date = '2024-07-12';
    //   }

    //   // 更新米数 (示例计算)
    //   const totalMeters = 1530;
    //   const currentMeters = Math.floor(
    //     (totalMeters * (this.currentPosition - 20)) / 80,
    //   );
    //   this.markingData.meter = `${1231}m`;
    // },
    updateMarkingData() {
      const totalPoints = this.xData.length;
      if (totalPoints === 0) return; // 边界保护

      // 关键修复：基于 currentPosition 0-100% 计算刻度索引
      const progressRatio = this.currentPosition / 100; // 进度占比（0-1）
      // 计算索引：占比 * 总刻度数，取floor避免超出，同时限制最小为0
      let pointIndex = Math.floor(progressRatio * totalPoints);
      pointIndex = Math.min(totalPoints - 1, Math.max(0, pointIndex));

      // 修复1：日期随刻度更新（不再硬编码）
      if (this.xData[pointIndex]) {
        this.markingData.date = this.dayFormat(this.xData[pointIndex].value);
      }

      // 修复2：米数随进度更新（不再硬编码）
      const totalMeters = parseInt(this.panelData[0].value); // 从panelData取设计总长度（1530m）
      const currentMeters = Math.floor(totalMeters * progressRatio); // 按进度比例计算米数
      this.markingData.meter = `${currentMeters}m`;
    },
    selectProject(node) {
      this.nodeData = node;
    },
    handlerProgressChange(data) {
      this.calculateMarkerPosition();
      this.calculatePlayRange();
      // this.handleInit()
      // console.log(1231231,this.generateMonthlyFirstDays())
    },
    async handleInit() {
      console.log(this.nodeData);

      const params = {
        time: this.$dayjs().startOf('year').format('YYYY-MM-DD'),
        holeType: 'BRANCH',
        statisticsType: 'YEAR',
        procedureName: '',
        workFaceName: '',
        pageSize: '15',
        pageNo: '1',
      };
      //获取施工进度左侧数据
      const res = await getPlanDetail(params);
    },
    zoomHandle() {
      window.eventHub.$emit('onProgressChange', { isShow: false });
    },
    generateMonthlyFirstDays(inputDate = '2024-07-05') {
      // 1. 定义起始日期（2024年7月1日）和终止日期（当前月第一天）
      const start = this.$dayjs(inputDate).startOf('month'); // 起始月第一天
      // const end = this.$dayjs().startOf('month'); // 当前月第一天（避免生成未来月）
      const end = this.$dayjs().endOf('month'); // 当前月最后一天

      const firstDayList = [];
      let current = start; // 循环用的当前日期

      // 2. 循环：从起始月到当前月，逐个添加每月第一天
      // 注意：使用isBefore（end是否在current之前） 和isSame（end是否与current同月）确保包含终止月
      while (current.isBefore(end) || current.isSame(end, 'month')) {
        // 格式化为 "YYYY-MM-DD" 字符串并推入数组
        firstDayList.push(current.format('YYYY-MM-DD'));
        // 月份加1，自动处理跨年（如12月+1 → 次年1月）
        current = current.add(1, 'month');
      }
      // 包含终止月的最后一天
      if (!firstDayList.includes(end.format('YYYY-MM-DD'))) {
        firstDayList.push(end.format('YYYY-MM-DD'));
      }
      return firstDayList;
    },
  },
  beforeDestroy() {
    // window.eventHub.$on('onProgressChange', this.handlerProgressChange)
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId);
    }
  },
};
</script>

<style scoped>
.play-content {
  display: flex;
  align-items: center;
  font-size: 14px;
  justify-content: flex-end;
}
.play-select {
  display: flex;
  align-items: center;
  margin-left: 50px;
  font-size: 14px;
}
.play-button {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  .play {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 20px;
    box-sizing: border-box;
    border: 1.5px solid rgba(0, 107, 237, 0.3);
    margin-left: 10px;
    cursor: pointer;
    img {
      width: 50%;
      height: 50%;
    }
  }
  .play1 {
    width: 32px;
    height: 32px;
  }
}
.rock_chart {
  position: absolute;
  bottom: 74px;
  left: 23%;
  width: 55%;
  height: 25%;
  /* // width: 100%; */
  /* // height: 100%; */
  padding: 15px;
  border-width: 3px;
  border-style: solid;
  border-color: white;
  border-radius: 12px;
  background-color: #f4f7fa;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  /* // overflow-y: hidden; */
}

.title_right_content {
  display: flex;
  align-items: center;

  .right_title_info {
    margin-right: 15px;
    font-size: 12px;
    color: #666666;
  }

  img {
    width: 14px;
    height: 14px;
    cursor: pointer;
  }
}

.trend_chart_box {
  display: flex;
  /* // flex-direction: column; */
  justify-content: space-between;
  width: 100%;
  /* // height: 158px; */
  height: calc(100% - 30px);
  position: relative;
  .chart_box_left {
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    width: 140px;
    .panel-item {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      justify-content: center;
      padding-left: 12px;
      width: 125px;
      height: 54px;
      font-size: 14px;
      border-radius: 4px;
      box-sizing: border-box;
      border: 1px solid rgba(0, 107, 237, 0.2);
    }
  }
  .chart_box_right {
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    width: calc(100% - 165px);
    .progress-box {
      position: relative;
      display: flex;
      flex-direction: column;
      width: 100%;
      height: 80%;
      justify-content: center;
      padding: 0;
      margin: 0;
    }
    .progress-content {
      display: flex;
      width: 100%;
      height: 20px;
      font-size: 12px;
      background: #999;
      border-radius: 20px;
      color: #fff;
      overflow: hidden;
    }
    .progress-history {
      display: flex;
      align-items: center;
      justify-content: center;
      background: linear-gradient(90deg, #97df97 0%, #63cb63 100%);
    }
    .progress-future {
      display: flex;
      align-items: center;
      justify-content: center;
      background: linear-gradient(270deg, #a1a1a1 0%, #bfbfbf 100%);
    }
    .progress-scale {
      display: flex;
      width: 100%;
      .progress-scale-item {
        position: relative;
        font-size: 12px;
        .progress-scale-line {
          width: 1px;
          height: 6px;
          background-color: #999;
        }
        .progress-scale-son {
          position: absolute;
          left: -20%;
        }
      }
    }
    .marking-line {
      position: absolute;
      top: 50%;
      width: 0;
      height: 60%;
      border-left: 0.125rem solid #1890ff;
      transition: left 0.3s ease; /* 平滑过渡，减少视觉跳动 */
      z-index: 2;
      transform: translateY(-50%);
      color: #1890ff;
    }
    .marking-line:after {
      content: ''; /* 伪元素必须有 content 属性 */
      position: absolute;
      top: -5px;
      right: -5px;

      /* 三角样式 */
      width: 0;
      height: 0;
      border-left: 5px solid transparent;
      border-right: 5px solid transparent;
      border-top: 5px solid #1890ff; /* 上边框有颜色，形成向下三角 */
    }
    .line-row1 {
      font-size: 12px;
      width: 90px;
      display: inline-block;
      position: absolute;
      bottom: -20px;
      left: -45px;
      text-align: center;
    }
    .line-row2 {
      font-size: 12px;
      width: 70px;
      display: inline-block;
      position: absolute;
      top: -20px;
      left: -35px;
      text-align: center;
    }
  }
}

::v-deep .SecondTitle .title {
  font-weight: bold;
}

.legend {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  height: 32px;
  gap: 16px;

  .legend-item {
    display: flex;
    align-items: center;
    gap: 4px;

    .legend-dot {
      width: 10px;
      height: 10px;
    }

    .legend-text {
      font-size: 12px;
      color: #666;
    }
  }
}
</style>
